home *** CD-ROM | disk | FTP | other *** search
/ Aminet 30 / Aminet 30 (1999)(Schatztruhe)[!][Apr 1999].iso / Aminet / gfx / misc / gnuplot-3.7src.lha / gnuplot-3.7src / gnuplot-3.7.lha / gnuplot-3.7 / readline.c < prev    next >
C/C++ Source or Header  |  1998-11-03  |  28KB  |  1,105 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: readline.c,v 1.69 1998/04/14 00:16:12 drd Exp $";
  3. #endif
  4.  
  5. /* GNUPLOT - readline.c */
  6.  
  7. /*[
  8.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted,
  12.  * provided that the above copyright notice appear in all copies and
  13.  * that both that copyright notice and this permission notice appear
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the complete modified source code.  Modifications are to
  18.  * be distributed as patches to the released version.  Permission to
  19.  * distribute binaries produced by compiling modified sources is granted,
  20.  * provided you
  21.  *   1. distribute the corresponding source modifications from the
  22.  *    released version in the form of a patch file along with the binaries,
  23.  *   2. add special version identification to distinguish your version
  24.  *    in addition to the base release version number,
  25.  *   3. provide your name and address as the primary contact for the
  26.  *    support of your modified version, and
  27.  *   4. retain our contact information in regard to use of the base
  28.  *    software.
  29.  * Permission to distribute the released version of the source code along
  30.  * with corresponding source modifications in the form of a patch file is
  31.  * granted with same provisions 2 through 4 for binary distributions.
  32.  *
  33.  * This software is provided "as is" without express or implied warranty
  34.  * to the extent permitted by applicable law.
  35. ]*/
  36.  
  37.  
  38. /* 
  39.  * AUTHORS
  40.  *
  41.  *   Original Software:
  42.  *     Tom Tkacik
  43.  *
  44.  *   Msdos port and some enhancements:
  45.  *     Gershon Elber and many others.
  46.  *
  47.  *   In add_history(), do not store duplicated entries:
  48.  *     Petr Mikulik
  49.  */
  50.  
  51. #include <signal.h>
  52. /* get prototype for alloc and gpfaralloc */
  53. #include "plot.h"
  54.  
  55. #if defined(READLINE) && !defined(GNU_READLINE)
  56.  
  57. /* a small portable version of GNU's readline
  58.  * this is not the BASH or GNU EMACS version of READLINE due to Copyleft 
  59.  * restrictions
  60.  * do not need any terminal capabilities except backspace,
  61.  * and space overwrites a character
  62.  */
  63.  
  64. /* NANO-EMACS line editing facility
  65.  * printable characters print as themselves (insert not overwrite)
  66.  * ^A moves to the beginning of the line
  67.  * ^B moves back a single character
  68.  * ^E moves to the end of the line
  69.  * ^F moves forward a single character
  70.  * ^K kills from current position to the end of line
  71.  * ^P moves back through history
  72.  * ^N moves forward through history
  73.  * ^H and DEL delete the previous character
  74.  * ^D deletes the current character, or EOF if line is empty
  75.  * ^L/^R redraw line in case it gets trashed
  76.  * ^U kills the entire line
  77.  * ^W kills last word
  78.  * LF and CR return the entire line regardless of the cursor postition
  79.  * EOF with an empty line returns (char *)NULL
  80.  *
  81.  * all other characters are ignored
  82.  */
  83.  
  84. #ifdef __linux__
  85. /* HBB: to get prototype for ioctl() */
  86. # include <sys/ioctl.h>
  87. #endif
  88.  
  89. /* replaces the previous klugde in configure */
  90. #if defined(HAVE_TERMIOS_H) && defined(HAVE_TCGETATTR)
  91. # define TERMIOS
  92. #else /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
  93. # ifdef HAVE_SGTTY_H
  94. #  define SGTTY
  95. # endif
  96. #endif /* not HAVE_TERMIOS_H && HAVE_TCGETATTR */
  97.  
  98. #if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386) && !defined(OSK)
  99.  
  100. /*
  101.  * Set up structures using the proper include file
  102.  */
  103. # if defined(_IBMR2) || defined(alliant)
  104. #  define SGTTY
  105. # endif
  106.  
  107. /*  submitted by Francois.Dagorn@cicb.fr */
  108. # ifdef SGTTY
  109. #  include <sgtty.h>
  110. static struct sgttyb orig_termio, rl_termio;
  111. /* define terminal control characters */
  112. static struct tchars s_tchars;
  113. #  ifndef VERASE
  114. #   define VERASE    0
  115. #  endif            /* not VERASE */
  116. #  ifndef VEOF
  117. #   define VEOF      1
  118. #  endif            /* not VEOF */
  119. #  ifndef VKILL
  120. #   define VKILL     2
  121. #  endif            /* not VKILL */
  122. #  ifdef TIOCGLTC        /* available only with the 'new' line discipline */
  123. static struct ltchars s_ltchars;
  124. #   ifndef VWERASE
  125. #    define VWERASE   3
  126. #   endif            /* not VWERASE */
  127. #   ifndef VREPRINT
  128. #    define VREPRINT  4
  129. #   endif            /* not VREPRINT */
  130. #   ifndef VSUSP
  131. #    define VSUSP     5
  132. #   endif            /* not VSUP */
  133. #  endif            /* TIOCGLTC */
  134. #  ifndef NCCS
  135. #   define NCCS      6
  136. #  endif            /* not NCCS */
  137.  
  138. # else                /* not SGTTY */
  139.  
  140. /* SIGTSTP defines job control
  141.  * if there is job control then we need termios.h instead of termio.h
  142.  * (Are there any systems with job control that use termio.h?  I hope not.)
  143.  */
  144. #  if defined(SIGTSTP) || defined(TERMIOS)
  145. #   ifndef TERMIOS
  146. #    define TERMIOS
  147. #   endif            /* not TERMIOS */
  148. #   include <termios.h>
  149. /* Added by Robert Eckardt, RobertE@beta.TP2.Ruhr-Uni-Bochum.de */
  150. #   ifdef ISC22
  151. #    ifndef ONOCR        /* taken from sys/termio.h */
  152. #     define ONOCR 0000020    /* true at least for ISC 2.2 */
  153. #    endif            /* not ONOCR */
  154. #    ifndef IUCLC
  155. #     define IUCLC 0001000
  156. #    endif            /* not IUCLC */
  157. #   endif            /* ISC22 */
  158. #   if !defined(IUCLC)
  159.      /* translate upper to lower case not supported */
  160. #    define IUCLC 0
  161. #   endif            /* not IUCLC */
  162.  
  163. static struct termios orig_termio, rl_termio;
  164. #  else                /* not SIGSTP || TERMIOS */
  165. #   include <termio.h>
  166. static struct termio orig_termio, rl_termio;
  167. /* termio defines NCC instead of NCCS */
  168. #   define NCCS    NCC
  169. #  endif            /* not SIGTSTP || TERMIOS */
  170. # endif                /* SGTTY */
  171.  
  172. /* ULTRIX defines VRPRNT instead of VREPRINT */
  173. # if defined(VRPRNT) && !defined(VREPRINT)
  174. #  define VREPRINT VRPRNT
  175. # endif                /* VRPRNT */
  176.  
  177. /* define characters to use with our input character handler */
  178. static char term_chars[NCCS];
  179.  
  180. static int term_set = 0;    /* =1 if rl_termio set */
  181.  
  182. #define special_getc() ansi_getc()
  183. static int ansi_getc __PROTO((void));
  184.  
  185. #else /* MSDOS or ATARI or MTOS or _Windows or DOS386 or OSK */
  186.  
  187. # ifdef _Windows
  188. #  include <windows.h>
  189. #  include "win/wtext.h"
  190. #  include "win/wgnuplib.h"
  191. extern TW textwin;
  192. #  define TEXTUSER 0xf1
  193. #  define TEXTGNUPLOT 0xf0
  194. #  define special_getc() msdos_getch()
  195. static char msdos_getch __PROTO((void));    /* HBB 980308: PROTO'ed it */
  196. # endif                /* _Windows */
  197.  
  198. # if defined(MSDOS) || defined(DOS386)
  199. /* MSDOS specific stuff */
  200. #  ifdef DJGPP
  201. #   include <pc.h>
  202. #  endif            /* DJGPP */
  203. #  ifdef __EMX__
  204. #   include <conio.h>
  205. #  endif            /* __EMX__ */
  206. #  define special_getc() msdos_getch()
  207. static char msdos_getch();
  208. # endif                /* MSDOS || DOS386 */
  209.  
  210. # ifdef OSK
  211. #  include <sgstat.h>
  212. #  include <modes.h>
  213.  
  214. #  define STDIN    0
  215. static int term_set = 0;    /* =1 if new_settings is set */
  216.  
  217. static struct _sgs old_settings;    /* old terminal settings        */
  218. static struct _sgs new_settings;    /* new terminal settings        */
  219.  
  220. #  define special_getc() ansi_getc()
  221. static int ansi_getc __PROTO((void));
  222.  
  223. /* On OS9 a '\n' is a character 13 and '\r' == '\n'. This gives troubles
  224.    here, so we need a new putc wich handles this correctly and print a
  225.    character 10 on each place we want a '\n'.
  226.  */
  227. #  undef putc            /* Undefine the macro for putc */
  228.  
  229. static int putc(c, fp)
  230. char c;
  231. FILE *fp;
  232. {
  233.     write(fileno(fp), &c, 1);
  234.     if (c == '\012') {        /* A normal ASCII '\n' */
  235.     c = '\r';
  236.     write(fileno(fp), &c, 1);
  237.     }
  238. }
  239.  
  240. # endif                /* OSK */
  241.  
  242. # if defined(ATARI) || defined(MTOS)
  243. #  define special_getc() tos_getch()
  244. # endif                /* ATARI || MTOS */
  245.  
  246. #endif /* MSDOS or ATARI or MTOS or _Windows or DOS386 or OSK */
  247.  
  248. #ifdef OS2
  249. # if defined( special_getc )
  250. #  undef special_getc()
  251. # endif                /* special_getc */
  252. # define special_getc() msdos_getch()
  253. static char msdos_getch __PROTO((void));    /* HBB 980308: PROTO'ed it */
  254. #endif /* OS2 */
  255.  
  256.  
  257. /* initial size and increment of input line length */
  258. #define MAXBUF    1024
  259. /* ^H */
  260. #define BACKSPACE 0x08
  261. #define SPACE    ' '
  262.  
  263. #ifdef OSK
  264. # define NEWLINE    '\012'
  265. #else /* OSK */
  266. # define NEWLINE    '\n'
  267. #endif /* not OSK */
  268.  
  269. struct hist {
  270.     char *line;
  271.     struct hist *prev;
  272.     struct hist *next;
  273. };
  274.  
  275. static struct hist *history = NULL;    /* no history yet */
  276. static struct hist *cur_entry = NULL;
  277.  
  278. static char *cur_line;        /* current contents of the line */
  279. static int line_len = 0;
  280. static int cur_pos = 0;        /* current position of the cursor */
  281. static int max_pos = 0;        /* maximum character position */
  282.  
  283.  
  284. static void fix_line __PROTO((void));
  285. static void redraw_line __PROTO((char *prompt));
  286. static void clear_line __PROTO((char *prompt));
  287. static void clear_eoline __PROTO((void));
  288. static void copy_line __PROTO((char *line));
  289. static void set_termio __PROTO((void));
  290. static void reset_termio __PROTO((void));
  291. static int ansi_getc __PROTO((void));
  292. static int user_putc __PROTO((int ch));
  293. static int user_puts __PROTO((char *str));
  294. static void backspace __PROTO((void));
  295. static void extend_cur_line __PROTO((void));
  296.  
  297. /* user_putc and user_puts should be used in the place of
  298.  * fputc(ch,stderr) and fputs(str,stderr) for all output
  299.  * of user typed characters.  This allows MS-Windows to 
  300.  * display user input in a different color.
  301.  */
  302. static int user_putc(ch)
  303. int ch;
  304. {
  305.     int rv;
  306. #ifdef _Windows
  307.     TextAttr(&textwin, TEXTUSER);
  308. #endif
  309.     rv = fputc(ch, stderr);
  310. #ifdef _Windows
  311.     TextAttr(&textwin, TEXTGNUPLOT);
  312. #endif
  313.     return rv;
  314. }
  315.  
  316. static int user_puts(str)
  317. char *str;
  318. {
  319.     int rv;
  320. #ifdef _Windows
  321.     TextAttr(&textwin, TEXTUSER);
  322. #endif
  323.     rv = fputs(str, stderr);
  324. #ifdef _Windows
  325.     TextAttr(&textwin, TEXTGNUPLOT);
  326. #endif
  327.     return rv;
  328. }
  329.  
  330. /* This function provides a centralized non-destructive backspace capability
  331.  * M. Castro
  332.  */
  333. static void backspace()
  334. {
  335.     user_putc(BACKSPACE);
  336. }
  337.  
  338. static void extend_cur_line()
  339. {
  340.     char *new_line;
  341.  
  342.     /* extent input line length */
  343.     new_line = gp_realloc(cur_line, line_len + MAXBUF, NULL);
  344.     if (!new_line) {
  345.     reset_termio();
  346.     int_error("Can't extend readline length", NO_CARET);
  347.     }
  348.     cur_line = new_line;
  349.     line_len += MAXBUF;
  350.     FPRINTF((stderr, "\nextending readline length to %d chars\n", line_len));
  351. }
  352.  
  353. char *
  354.  readline(prompt)
  355. char *prompt;
  356. {
  357.  
  358.     int cur_char;
  359.     char *new_line;
  360.  
  361.     /* start with a string of MAXBUF chars */
  362.  
  363.     if (line_len != 0) {
  364.     free(cur_line);
  365.     line_len = 0;
  366.     }
  367.     cur_line = gp_alloc((unsigned long) MAXBUF, "readline");
  368.     line_len = MAXBUF;
  369.  
  370.     /* set the termio so we can do our own input processing */
  371.     set_termio();
  372.  
  373.     /* print the prompt */
  374.     fputs(prompt, stderr);
  375.     cur_line[0] = '\0';
  376.     cur_pos = 0;
  377.     max_pos = 0;
  378.     cur_entry = NULL;
  379.  
  380.     /* get characters */
  381.     for (;;) {
  382.     cur_char = special_getc();
  383.  
  384. /*
  385.  * The #define CHARSET7BIT should be used when one encounters problems with
  386.  * 8bit characters that should not be entered on the commandline. I cannot
  387.  * think on any reasonable example where this could happen, but what do I know?
  388.  * After all, the unix world still ignores 8bit chars in most applications.
  389.  *
  390.  * Note that latin1 defines the chars 0x80-0x9f as control chars. For the
  391.  * benefit of Atari, MSDOS, Windows and NeXT I have decided to ignore this,
  392.  * since it would require more #ifs.
  393.  *
  394.  */
  395.  
  396. #ifdef CHARSET7BIT
  397.     if (isprint(cur_char)) {
  398. #else /* CHARSET7BIT */
  399.     if (isprint(cur_char) || (((unsigned char) cur_char > 0x7f) &&
  400.                   cur_char != EOF)) {
  401. #endif /* CHARSET7BIT */
  402.         int i;
  403.  
  404.         if (max_pos + 1 >= line_len) {
  405.         extend_cur_line();
  406.         }
  407.         for (i = max_pos; i > cur_pos; i--) {
  408.         cur_line[i] = cur_line[i - 1];
  409.         }
  410.         user_putc(cur_char);
  411.         cur_line[cur_pos] = cur_char;
  412.         cur_pos += 1;
  413.         max_pos += 1;
  414.         if (cur_pos < max_pos)
  415.         fix_line();
  416.         cur_line[max_pos] = '\0';
  417.  
  418.         /* else interpret unix terminal driver characters */
  419. #ifdef VERASE
  420.     } else if (cur_char == term_chars[VERASE]) {    /* DEL? */
  421.         if (cur_pos > 0) {
  422.         int i;
  423.         cur_pos -= 1;
  424.         backspace();
  425.         for (i = cur_pos; i < max_pos; i++)
  426.             cur_line[i] = cur_line[i + 1];
  427.         max_pos -= 1;
  428.         fix_line();
  429.         }
  430. #endif /* VERASE */
  431. #ifdef VEOF
  432.     } else if (cur_char == term_chars[VEOF]) {    /* ^D? */
  433.         if (max_pos == 0) {
  434.         reset_termio();
  435.         return ((char *) NULL);
  436.         }
  437.         if ((cur_pos < max_pos) && (cur_char == 004)) {    /* ^D */
  438.         int i;
  439.         for (i = cur_pos; i < max_pos; i++)
  440.             cur_line[i] = cur_line[i + 1];
  441.         max_pos -= 1;
  442.         fix_line();
  443.         }
  444. #endif /* VEOF */
  445. #ifdef VKILL
  446.     } else if (cur_char == term_chars[VKILL]) {    /* ^U? */
  447.         clear_line(prompt);
  448. #endif /* VKILL */
  449. #ifdef VWERASE
  450.     } else if (cur_char == term_chars[VWERASE]) {    /* ^W? */
  451.         while ((cur_pos > 0) &&
  452.            (cur_line[cur_pos - 1] == SPACE)) {
  453.         cur_pos -= 1;
  454.         backspace();
  455.         }
  456.         while ((cur_pos > 0) &&
  457.            (cur_line[cur_pos - 1] != SPACE)) {
  458.         cur_pos -= 1;
  459.         backspace();
  460.         }
  461.         clear_eoline();
  462.         max_pos = cur_pos;
  463. #endif /* VWERASE */
  464. #ifdef VREPRINT
  465.     } else if (cur_char == term_chars[VREPRINT]) {    /* ^R? */
  466.         putc(NEWLINE, stderr);    /* go to a fresh line */
  467.         redraw_line(prompt);
  468. #endif /* VREPRINT */
  469. #ifdef VSUSP
  470.     } else if (cur_char == term_chars[VSUSP]) {
  471.         reset_termio();
  472.         kill(0, SIGTSTP);
  473.  
  474.         /* process stops here */
  475.  
  476.         set_termio();
  477.         /* print the prompt */
  478.         redraw_line(prompt);
  479. #endif /* VSUSP */
  480.     } else {
  481.         /* do normal editing commands */
  482.         /* some of these are also done above */
  483.         int i;
  484.         switch (cur_char) {
  485.         case EOF:
  486.         reset_termio();
  487.         return ((char *) NULL);
  488.         case 001:        /* ^A */
  489.         while (cur_pos > 0) {
  490.             cur_pos -= 1;
  491.             backspace();
  492.         }
  493.         break;
  494.         case 002:        /* ^B */
  495.         if (cur_pos > 0) {
  496.             cur_pos -= 1;
  497.             backspace();
  498.         }
  499.         break;
  500.         case 005:        /* ^E */
  501.         while (cur_pos < max_pos) {
  502.             user_putc(cur_line[cur_pos]);
  503.             cur_pos += 1;
  504.         }
  505.         break;
  506.         case 006:        /* ^F */
  507.         if (cur_pos < max_pos) {
  508.             user_putc(cur_line[cur_pos]);
  509.             cur_pos += 1;
  510.         }
  511.         break;
  512.         case 013:        /* ^K */
  513.         clear_eoline();
  514.         max_pos = cur_pos;
  515.         break;
  516.         case 020:        /* ^P */
  517.         if (history != NULL) {
  518.             if (cur_entry == NULL) {
  519.             cur_entry = history;
  520.             clear_line(prompt);
  521.             copy_line(cur_entry->line);
  522.             } else if (cur_entry->prev != NULL) {
  523.             cur_entry = cur_entry->prev;
  524.             clear_line(prompt);
  525.             copy_line(cur_entry->line);
  526.             }
  527.         }
  528.         break;
  529.         case 016:        /* ^N */
  530.         if (cur_entry != NULL) {
  531.             cur_entry = cur_entry->next;
  532.             clear_line(prompt);
  533.             if (cur_entry != NULL)
  534.             copy_line(cur_entry->line);
  535.             else
  536.             cur_pos = max_pos = 0;
  537.         }
  538.         break;
  539.         case 014:        /* ^L */
  540.         case 022:        /* ^R */
  541.         putc(NEWLINE, stderr);    /* go to a fresh line */
  542.         redraw_line(prompt);
  543.         break;
  544.         case 0177:        /* DEL */
  545.         case 010:        /* ^H */
  546.         if (cur_pos > 0) {
  547.             cur_pos -= 1;
  548.             backspace();
  549.             for (i = cur_pos; i < max_pos; i++)
  550.             cur_line[i] = cur_line[i + 1];
  551.             max_pos -= 1;
  552.             fix_line();
  553.         }
  554.         break;
  555.         case 004:        /* ^D */
  556.         if (max_pos == 0) {
  557.             reset_termio();
  558.             return ((char *) NULL);
  559.         }
  560.         if (cur_pos < max_pos) {
  561.             for (i = cur_pos; i < max_pos; i++)
  562.             cur_line[i] = cur_line[i + 1];
  563.             max_pos -= 1;
  564.             fix_line();
  565.         }
  566.         break;
  567.         case 025:        /* ^U */
  568.         clear_line(prompt);
  569.         break;
  570.         case 027:        /* ^W */
  571.         while ((cur_pos > 0) &&
  572.                (cur_line[cur_pos - 1] == SPACE)) {
  573.             cur_pos -= 1;
  574.             backspace();
  575.         }
  576.         while ((cur_pos > 0) &&
  577.                (cur_line[cur_pos - 1] != SPACE)) {
  578.             cur_pos -= 1;
  579.             backspace();
  580.         }
  581.         clear_eoline();
  582.         max_pos = cur_pos;
  583.         break;
  584.         case '\n':        /* ^J */
  585. #ifndef OSK
  586.         case '\r':        /* ^M */
  587. #endif
  588.         cur_line[max_pos + 1] = '\0';
  589. #ifdef OS2
  590.         while (cur_pos < max_pos) {
  591.             user_putc(cur_line[cur_pos]);
  592.             cur_pos += 1;
  593.         }
  594. #endif
  595.         putc(NEWLINE, stderr);
  596.  
  597.         /* Shrink the block down to fit the string ?
  598.          * if the alloc fails, we still own block at cur_line,
  599.          * but this shouldn't really fail.
  600.          */
  601.         new_line = (char *) gp_realloc(cur_line, (unsigned long) (strlen(cur_line) + 1), "line resize");
  602.         if (new_line)
  603.             cur_line = new_line;
  604.         /* else we just hang on to what we had - it's not a problem */
  605.  
  606.         line_len = 0;
  607.         FPRINTF((stderr, "Resizing input line to %d chars\n", strlen(cur_line)));
  608.         reset_termio();
  609.         return (cur_line);
  610.         default:
  611.         break;
  612.         }
  613.     }
  614.     }
  615. }
  616.  
  617. /* fix up the line from cur_pos to max_pos
  618.  * do not need any terminal capabilities except backspace,
  619.  * and space overwrites a character
  620.  */
  621. static void fix_line()
  622. {
  623.     int i;
  624.  
  625.     /* write tail of string */
  626.     for (i = cur_pos; i < max_pos; i++)
  627.     user_putc(cur_line[i]);
  628.  
  629.     /* write a space at the end of the line in case we deleted one */
  630.     user_putc(SPACE);
  631.  
  632.     /* backup to original position */
  633.     for (i = max_pos + 1; i > cur_pos; i--)
  634.     backspace();
  635.  
  636. }
  637.  
  638. /* redraw the entire line, putting the cursor where it belongs */
  639. static void redraw_line(prompt)
  640. char *prompt;
  641. {
  642.     int i;
  643.  
  644.     fputs(prompt, stderr);
  645.     user_puts(cur_line);
  646.  
  647.     /* put the cursor where it belongs */
  648.     for (i = max_pos; i > cur_pos; i--)
  649.     backspace();
  650. }
  651.  
  652. /* clear cur_line and the screen line */
  653. static void clear_line(prompt)
  654. char *prompt;
  655. {
  656.     int i;
  657.     for (i = 0; i < max_pos; i++)
  658.     cur_line[i] = '\0';
  659.  
  660.     for (i = cur_pos; i > 0; i--)
  661.     backspace();
  662.  
  663.     for (i = 0; i < max_pos; i++)
  664.     putc(SPACE, stderr);
  665.  
  666.     putc('\r', stderr);
  667.     fputs(prompt, stderr);
  668.  
  669.     cur_pos = 0;
  670.     max_pos = 0;
  671. }
  672.  
  673. /* clear to end of line and the screen end of line */
  674. static void clear_eoline()
  675. {
  676.     int i;
  677.     for (i = cur_pos; i < max_pos; i++)
  678.     cur_line[i] = '\0';
  679.  
  680.     for (i = cur_pos; i < max_pos; i++)
  681.     putc(SPACE, stderr);
  682.     for (i = cur_pos; i < max_pos; i++)
  683.     backspace();
  684. }
  685.  
  686. /* copy line to cur_line, draw it and set cur_pos and max_pos */
  687. static void copy_line(line)
  688. char *line;
  689. {
  690.     while (strlen(line) + 1 > line_len) {
  691.     extend_cur_line();
  692.     }
  693.     strcpy(cur_line, line);
  694.     user_puts(cur_line);
  695.     cur_pos = max_pos = strlen(cur_line);
  696. }
  697.  
  698. /* add line to the history */
  699. void add_history(line)
  700. char *line;
  701. {
  702.     struct hist *entry;
  703.  
  704.     entry = history;
  705.     while (entry != NULL) {
  706.     /* Don't store duplicate entries */
  707.     if (!strcmp(entry->line, line)) {
  708.         /* cmd lines are equal, relink entry that was found last */
  709.         if (entry->next == NULL) {
  710.         /* previous command repeated, no change */
  711.         return;
  712.         }
  713.         if (entry->prev == NULL) {
  714.         /* current cmd line equals the first in the history */
  715.         (entry->next)->prev = NULL;
  716.         history->next = entry;
  717.         entry->prev = history;
  718.         entry->next = NULL;
  719.         history = entry;
  720.         return;
  721.         }
  722.         /* bridge over entry's vacancy, then move it to the end */
  723.         (entry->prev)->next = entry->next;
  724.         (entry->next)->prev = entry->prev;
  725.         entry->prev = history;
  726.         history->next = entry;
  727.         entry->next = NULL;
  728.         history = entry;
  729.         return;
  730.     }
  731.     entry = entry->prev;
  732.     }                /* end of not-storing duplicated entries */
  733.  
  734.     entry = (struct hist *) gp_alloc((unsigned long) sizeof(struct hist), "history");
  735.     entry->line = gp_alloc((unsigned long) (strlen(line) + 1), "history");
  736.     strcpy(entry->line, line);
  737.  
  738.     entry->prev = history;
  739.     entry->next = NULL;
  740.     if (history != NULL) {
  741.     history->next = entry;
  742.     }
  743.     history = entry;
  744. }
  745.  
  746.  
  747. /* Convert ANSI arrow keys to control characters */
  748. static int ansi_getc()
  749. {
  750.     int c = getc(stdin);
  751.     if (c == 033) {
  752.     c = getc(stdin);    /* check for CSI */
  753.     if (c == '[') {
  754.         c = getc(stdin);    /* get command character */
  755.         switch (c) {
  756.         case 'D':        /* left arrow key */
  757.         c = 002;
  758.         break;
  759.         case 'C':        /* right arrow key */
  760.         c = 006;
  761.         break;
  762.         case 'A':        /* up arrow key */
  763.         c = 020;
  764.         break;
  765.         case 'B':        /* down arrow key */
  766.         c = 016;
  767.         break;
  768.         }
  769.     }
  770.     }
  771.     return c;
  772. }
  773.  
  774. #if defined(MSDOS) || defined(_Windows) || defined(DOS386) || defined(OS2)
  775.  
  776. /* Convert Arrow keystrokes to Control characters: */
  777. static char msdos_getch()
  778. {
  779. #ifdef DJGPP
  780.     char c;
  781.     int ch = getkey();
  782.     c = (ch & 0xff00) ? 0 : ch & 0xff;
  783. #else /* not DJGPP */
  784. # ifdef OS2
  785.     char c = getc(stdin);
  786. # else                /* not OS2 */
  787.     char c = getch();
  788. # endif                /* not OS2 */
  789. #endif /* not DJGPP */
  790.  
  791.     if (c == 0) {
  792. #ifdef DJGPP
  793.     c = ch & 0xff;
  794. #else /* not DJGPP */
  795. # ifdef OS2
  796.     c = getc(stdin);
  797. # else                /* not OS2 */
  798.     c = getch();        /* Get the extended code. */
  799. # endif                /* not OS2 */
  800. #endif /* not DJGPP */
  801.     switch (c) {
  802.     case 75:        /* Left Arrow. */
  803.         c = 002;
  804.         break;
  805.     case 77:        /* Right Arrow. */
  806.         c = 006;
  807.         break;
  808.     case 72:        /* Up Arrow. */
  809.         c = 020;
  810.         break;
  811.     case 80:        /* Down Arrow. */
  812.         c = 016;
  813.         break;
  814.     case 115:        /* Ctl Left Arrow. */
  815.     case 71:        /* Home */
  816.         c = 001;
  817.         break;
  818.     case 116:        /* Ctl Right Arrow. */
  819.     case 79:        /* End */
  820.         c = 005;
  821.         break;
  822.     case 83:        /* Delete */
  823.         c = 004;
  824.         break;
  825.     default:
  826.         c = 0;
  827.         break;
  828.     }
  829.     } else if (c == 033) {    /* ESC */
  830.     c = 025;
  831.     }
  832.     return c;
  833. }
  834.  
  835. #endif /* MSDOS || _Windows || DOS386 || OS2 */
  836.  
  837.  
  838. #if defined(ATARI) || defined(MTOS)
  839.  
  840. /* Convert Arrow keystrokes to Control characters: TOS version */
  841.  
  842. long poll_events(int);        /* from term/atariaes.trm */
  843.  
  844. /* this function is used in help.c as well. this means that the
  845.  * program doesn't work without -DREADLINE (which would be the case
  846.  * if help.c didn't use it as well, since no events would be processed)
  847.  */
  848. char tos_getch()
  849. {
  850.     long rawkey;
  851.     char c;
  852.     int scan_code;
  853.     static int in_help = 0;
  854.  
  855.     if (strcmp(term->name, "atari") == 0)
  856.     poll_events(0);
  857.  
  858.     if (in_help) {
  859.     switch (in_help) {
  860.     case 1:
  861.     case 5:
  862.         in_help++;
  863.         return 'e';
  864.     case 2:
  865.     case 6:
  866.         in_help++;
  867.         return 'l';
  868.     case 3:
  869.     case 7:
  870.         in_help++;
  871.         return 'p';
  872.     case 4:
  873.         in_help = 0;
  874.         return 0x0d;
  875.     case 8:
  876.         in_help = 0;
  877.         return ' ';
  878.     }
  879.     }
  880.     if (strcmp(term->name, "atari") == 0) {
  881.     do {
  882.         if (Bconstat(2))
  883.         rawkey = Cnecin();
  884.         else
  885.         rawkey = poll_events(1);
  886.     } while (rawkey == 0);
  887.     } else
  888.     rawkey = Cnecin();
  889.  
  890.     c = (char) rawkey;
  891.     scan_code = ((int) (rawkey >> 16)) & 0xff;    /* get the scancode */
  892.     if (Kbshift(-1) & 0x00000007)
  893.     scan_code |= 0x80;    /* shift or control ? */
  894.  
  895.     switch (scan_code) {
  896.     case 0x62:            /* HELP         */
  897.     case 0xe2:            /* shift HELP   */
  898.     if (max_pos == 0) {
  899.         if (scan_code == 0x62) {
  900.         in_help = 1;
  901.         } else {
  902.         in_help = 5;
  903.         }
  904.         return 'h';
  905.     } else {
  906.         return 0;
  907.     }
  908.     case 0x48:            /* Up Arrow */
  909.     return 0x10;        /* ^P */
  910.     case 0x50:            /* Down Arrow */
  911.     return 0x0e;        /* ^N */
  912.     case 0x4b:            /* Left Arrow */
  913.     return 0x02;        /* ^B */
  914.     case 0x4d:            /* Right Arrow */
  915.     return 0x06;        /* ^F */
  916.     case 0xcb:            /* Shift Left Arrow */
  917.     case 0xf3:            /* Ctrl Left Arrow (TOS-bug ?) */
  918.     case 0x47:            /* Home */
  919.     return 0x01;        /* ^A */
  920.     case 0xcd:            /* Shift Right Arrow */
  921.     case 0xf4:            /* Ctrl Right Arrow (TOS-bug ?) */
  922.     case 0xc7:            /* Shift Home */
  923.     case 0xf7:            /* Ctrl Home */
  924.     return 0x05;        /* ^E */
  925.     case 0x61:            /* Undo - redraw line */
  926.     return 0x0c;        /* ^L */
  927.     default:
  928.     if (c == 0x1b)
  929.         return 0x15;    /* ESC becomes ^U */
  930.     if (c == 0x7f)
  931.         return 0x04;    /* Del becomes ^D */
  932.     break;
  933.     }
  934.     return c;
  935. }
  936.  
  937. #endif /* ATARI || MTOS */
  938.  
  939.   /* set termio so we can do our own input processing */
  940. static void set_termio()
  941. {
  942. #if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386)
  943. /* set termio so we can do our own input processing */
  944. /* and save the old terminal modes so we can reset them later */
  945.     if (term_set == 0) {
  946.     /*
  947.      * Get terminal modes.
  948.      */
  949. # ifndef OSK
  950. #  ifdef SGTTY
  951.     ioctl(0, TIOCGETP, &orig_termio);
  952. #  else                /* not SGTTY */
  953. #   ifdef TERMIOS
  954. #    ifdef TCGETS
  955.     ioctl(0, TCGETS, &orig_termio);
  956. #    else            /* not TCGETS */
  957.     tcgetattr(0, &orig_termio);
  958. #    endif            /* not TCGETS */
  959. #   else            /* not TERMIOS */
  960.     ioctl(0, TCGETA, &orig_termio);
  961. #   endif            /* TERMIOS */
  962. #  endif            /* not SGTTY */
  963. # else                /* OSK */
  964.     setbuf(stdin, (char *) 0);    /* Make stdin and stdout unbuffered */
  965.     setbuf(stderr, (char *) 0);
  966.     _gs_opt(STDIN, &new_settings);
  967. # endif                /* OSK */
  968.  
  969.     /*
  970.      * Save terminal modes
  971.      */
  972. # ifndef OSK
  973.     rl_termio = orig_termio;
  974. # else                /* OSK */
  975.     _gs_opt(STDIN, &old_settings);
  976. # endif                /* OSK */
  977.  
  978.     /*
  979.      * Set the modes to the way we want them
  980.      *  and save our input special characters
  981.      */
  982. # ifndef OSK
  983. #  ifdef SGTTY
  984.     rl_termio.sg_flags |= CBREAK;
  985.     rl_termio.sg_flags &= ~(ECHO | XTABS);
  986.     ioctl(0, TIOCSETN, &rl_termio);
  987.  
  988.     ioctl(0, TIOCGETC, &s_tchars);
  989.     term_chars[VERASE] = orig_termio.sg_erase;
  990.     term_chars[VEOF] = s_tchars.t_eofc;
  991.     term_chars[VKILL] = orig_termio.sg_kill;
  992. #   ifdef TIOCGLTC
  993.     ioctl(0, TIOCGLTC, &s_ltchars);
  994.     term_chars[VWERASE] = s_ltchars.t_werasc;
  995.     term_chars[VREPRINT] = s_ltchars.t_rprntc;
  996.     term_chars[VSUSP] = s_ltchars.t_suspc;
  997.  
  998.     /* disable suspending process on ^Z */
  999.     s_ltchars.t_suspc = 0;
  1000.     ioctl(0, TIOCSLTC, &s_ltchars);
  1001. #   endif            /* TIOCGLTC */
  1002. #  else                /* not SGTTY */
  1003.     rl_termio.c_iflag &= ~(BRKINT | PARMRK | INPCK | IUCLC | IXON | IXOFF);
  1004.     rl_termio.c_iflag |= (IGNBRK | IGNPAR);
  1005.  
  1006.     /* rl_termio.c_oflag &= ~(ONOCR); Costas Sphocleous Irvine,CA */
  1007.  
  1008.     rl_termio.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL | NOFLSH);
  1009. #   ifdef OS2
  1010.     /* for emx: remove default terminal processing */
  1011.     rl_termio.c_lflag &= ~(IDEFAULT);
  1012. #   endif            /* OS2 */
  1013.     rl_termio.c_lflag |= (ISIG);
  1014.     rl_termio.c_cc[VMIN] = 1;
  1015.     rl_termio.c_cc[VTIME] = 0;
  1016.  
  1017. #   ifndef VWERASE
  1018. #    define VWERASE 3
  1019. #   endif            /* VWERASE */
  1020.     term_chars[VERASE] = orig_termio.c_cc[VERASE];
  1021.     term_chars[VEOF] = orig_termio.c_cc[VEOF];
  1022.     term_chars[VKILL] = orig_termio.c_cc[VKILL];
  1023. #   ifdef TERMIOS
  1024.     term_chars[VWERASE] = orig_termio.c_cc[VWERASE];
  1025. #    ifdef VREPRINT
  1026.     term_chars[VREPRINT] = orig_termio.c_cc[VREPRINT];
  1027. #    else            /* not VREPRINT */
  1028. #     ifdef VRPRNT
  1029.     term_chars[VRPRNT] = orig_termio.c_cc[VRPRNT];
  1030. #     endif            /* VRPRNT */
  1031. #    endif            /* not VREPRINT */
  1032.     term_chars[VSUSP] = orig_termio.c_cc[VSUSP];
  1033.  
  1034.     /* disable suspending process on ^Z */
  1035.     rl_termio.c_cc[VSUSP] = 0;
  1036. #   endif            /* TERMIOS */
  1037. #  endif            /* not SGTTY */
  1038. # else                /* OSK */
  1039.     new_settings._sgs_echo = 0;    /* switch off terminal echo */
  1040.     new_settings._sgs_pause = 0;    /* inhibit page pause */
  1041.     new_settings._sgs_eofch = 0;    /* inhibit eof  */
  1042.     new_settings._sgs_kbich = 0;    /* inhibit ^C   */
  1043.     new_settings._sgs_kbach = 0;    /* inhibit ^E   */
  1044. # endif                /* OSK */
  1045.  
  1046.     /*
  1047.      * Set the new terminal modes.
  1048.      */
  1049. # ifndef OSK
  1050. #  ifdef SGTTY
  1051.     ioctl(0, TIOCSLTC, &s_ltchars);
  1052. #  else                /* not SGTTY */
  1053. #   ifdef TERMIOS
  1054. #    ifdef TCSETSW
  1055.     ioctl(0, TCSETSW, &rl_termio);
  1056. #    else            /* not TCSETSW */
  1057.     tcsetattr(0, TCSADRAIN, &rl_termio);
  1058. #    endif            /* not TCSETSW */
  1059. #   else            /* not TERMIOS */
  1060.     ioctl(0, TCSETAW, &rl_termio);
  1061. #   endif            /* not TERMIOS */
  1062. #  endif            /* not SGTTY */
  1063. # else                /* OSK */
  1064.     _ss_opt(STDIN, &new_settings);
  1065. # endif                /* OSK */
  1066.     term_set = 1;
  1067.     }
  1068. #endif /* not MSDOS && not ATARI && not MTOS && not _Windows && not DOS386 */
  1069. }
  1070.  
  1071. static void reset_termio()
  1072. {
  1073. #if !defined(MSDOS) && !defined(ATARI) && !defined(MTOS) && !defined(_Windows) && !defined(DOS386)
  1074. /* reset saved terminal modes */
  1075.     if (term_set == 1) {
  1076. # ifndef OSK
  1077. #  ifdef SGTTY
  1078.     ioctl(0, TIOCSETN, &orig_termio);
  1079. #   ifdef TIOCGLTC
  1080.     /* enable suspending process on ^Z */
  1081.     s_ltchars.t_suspc = term_chars[VSUSP];
  1082.     ioctl(0, TIOCSLTC, &s_ltchars);
  1083. #   endif            /* TIOCGLTC */
  1084. #  else                /* not SGTTY */
  1085. #   ifdef TERMIOS
  1086. #    ifdef TCSETSW
  1087.     ioctl(0, TCSETSW, &orig_termio);
  1088. #    else            /* not TCSETSW */
  1089.     tcsetattr(0, TCSADRAIN, &orig_termio);
  1090. #    endif            /* not TCSETSW */
  1091. #   else            /* not TERMIOS */
  1092.     ioctl(0, TCSETAW, &orig_termio);
  1093. #   endif            /* TERMIOS */
  1094. #  endif            /* not SGTTY */
  1095. # else                /* OSK */
  1096.     _ss_opt(STDIN, &old_settings);
  1097. # endif                /* OSK */
  1098.     term_set = 0;
  1099.     }
  1100. #endif /* not MSDOS && not ATARI && not MTOS && not _Windows && not DOS386 */
  1101. }
  1102.  
  1103.  
  1104. #endif /* READLINE && not GNU_READLINE */
  1105.